home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xarchie-2.0.9 / db.c < prev    next >
C/C++ Source or Header  |  1995-06-18  |  9KB  |  432 lines

  1. /*
  2.  * db.c : Database routines for xarchie
  3.  *
  4.  * George Ferguson, ferguson@cs.rochester.edu, 2 Nov 1991.
  5.  * Version 2.0: 23 Apr 1993.
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include "db.h"
  10. #include "weight.h"
  11. #include "stringdefs.h"
  12. #include "debug.h"
  13.  
  14. #ifdef XARCHIE
  15. # include <X11/Intrinsic.h>
  16. #else /*!XARCHIE*/
  17. # include "xtypes.h"
  18. #endif
  19.  
  20. /*
  21.  * Functions defined here:
  22.  */
  23. DbEntry *newEntry();
  24. void clearEntries();
  25. DbEntry *addEntry();
  26. DbEntry *lastEntry();
  27. DbEntry *findEntryFromString();
  28. DbEntry *findEntryFromIndex();
  29. int findIndexFromEntry();
  30. void setEntryData(), freeEntryData();
  31. void sortEntriesRecursively(), sortEntries();
  32. int cmpEntryNames(), cmpEntryDates(), cmpEntryWeights();
  33.  
  34. static void clearEntriesInternal();
  35. static char *entryDate(),*hostDate(),*locationDate();
  36.  
  37. /*    -    -    -    -    -    -    -    -    */
  38.  
  39. DbEntry *
  40. newEntry()
  41. {
  42.     DbEntry *new;
  43.  
  44.     new = XtNew(DbEntry);
  45.     new->name = NULL;
  46.     new->type = DB_NOTYPE;
  47.     new->size = -1;
  48.     new->modes = "";
  49.     new->date = "";
  50.     new->gt_date = "";
  51.     new->vlink = NULL;
  52.     new->selected = -1;
  53.     new->entries = NULL;
  54.     new->next = new->prev = new->parent = NULL;
  55.     return(new);
  56. }
  57.  
  58. void
  59. clearEntries(dbp)
  60. DbEntry *dbp;
  61. {
  62.     if (dbp == NULL) {
  63.     fprintf(stderr,"DB Error: Attempt to clear NULL list\n");
  64.     return;
  65.     } else {
  66.     clearEntriesInternal(dbp->entries);
  67.     dbp->entries = NULL;
  68.     }
  69. }
  70.  
  71. static void
  72. clearEntriesInternal(dbp)
  73. DbEntry *dbp;
  74. {
  75.     DbEntry *t;
  76.  
  77.     while (dbp != NULL) {
  78.     clearEntriesInternal(dbp->entries);
  79.     freeEntryData(dbp);
  80.     t = dbp;
  81.     dbp = dbp->next;
  82.     XtFree((char *)t);
  83.     }
  84. }
  85.  
  86. /*    -    -    -    -    -    -    -    -    */
  87.  
  88. DbEntry *
  89. addEntry(parent,before)
  90. DbEntry *parent;
  91. DbEntry *before;
  92. {
  93.     DbEntry *new,*last;
  94.  
  95.     DEBUG2("adding entry to 0x%x before 0x%x\n",parent,before);
  96.     if (parent == NULL) {
  97.     fprintf(stderr,"DB error: attempt to add entry to NULL list\n");
  98.     return(NULL);
  99.     } else if (parent->entries == NULL) {
  100.     /* No items already in list */
  101.     DEBUG0("  inserting as new list\n");
  102.     new = XtNew(DbEntry);
  103.     DEBUG1("  new entry is 0x%x\n",new);
  104.     parent->entries = new;
  105.     new->prev = NULL;
  106.     new->next = NULL;
  107.     } else if (before == NULL) {
  108.     /* Insert at end of list */
  109.     DEBUG0("  inserting at end of list\n");
  110.     last = lastEntry(parent);
  111.     new = XtNew(DbEntry);
  112.     DEBUG1("  new entry is 0x%x\n",new);
  113.     last->next = new;
  114.     new->prev = last;
  115.     new->next = NULL;
  116.     } else if (before->prev == NULL) {
  117.     /* Insert at head of list */
  118.     DEBUG0("  inserting at head of list\n");
  119.     new = XtNew(DbEntry);
  120.     DEBUG1("  new entry is 0x%x\n",new);
  121.     parent->entries = new;
  122.     new->prev = NULL;
  123.     new->next = before;
  124.     before->prev = new;
  125.     } else {
  126.     /* Insert somewhere in the middle of list */
  127.     DEBUG0("  inserting in middle of list\n");
  128.     new = XtNew(DbEntry);
  129.     DEBUG1("  new entry is 0x%x\n",new);
  130.     before->prev->next = new;
  131.     new->prev = before->prev;
  132.     new->next = before;
  133.     before->prev = new;
  134.     }
  135.     new->parent = parent;
  136.     new->entries = NULL;
  137.     new->name = NULL;
  138.     new->type = DB_NOTYPE;
  139.     new->size = -1;
  140.     new->modes = "";
  141.     new->date = "";
  142.     new->gt_date = "";
  143.     new->vlink = NULL;
  144.     DEBUG0("  done adding new entry\n");
  145.     return(new);
  146. }
  147.  
  148. DbEntry *
  149. lastEntry(parent)
  150. DbEntry *parent;
  151. {
  152.     DbEntry *dbp;
  153.  
  154.     DEBUG1("finding last entry in entries for 0x%x\n",parent);
  155.     if (parent == NULL) {
  156.     fprintf(stderr,"DB error: attempt to find last entry of NULL list\n");
  157.     return(NULL);
  158.     } else if (parent->entries == NULL) {
  159.     DEBUG1("no entries for 0x%x, returning NULL\n",parent);
  160.     return(NULL);
  161.     } else {
  162.     for (dbp=parent->entries; dbp->next != NULL; dbp=dbp->next)
  163.         /* EMPTY */ ;
  164.     DEBUG2("last entry for 0x%x is 0x%x\n",parent,dbp);
  165.     return(dbp);
  166.     }
  167. }
  168.  
  169. DbEntry *
  170. findEntryFromString(parent,string)
  171. DbEntry *parent;
  172. char *string;
  173. {
  174.     DbEntry *dbp;
  175.  
  176.     DEBUG2("finding entry \"%s\" in entries for 0x%x\n",string,parent);
  177.     if (parent == NULL) {
  178.     fprintf(stderr,"DB error: attempt to find \"%s\" in NULL list",string);
  179.     return(NULL);
  180.     } else {
  181.     for (dbp=parent->entries; dbp != NULL &&
  182.                   strcmp(dbp->name,string) != 0; dbp=dbp->next)
  183.         /* EMPTY */ ;
  184.     DEBUG1("  find returning 0x%x\n",dbp);
  185.     return(dbp);
  186.     }
  187. }
  188.  
  189. DbEntry *
  190. findEntryFromIndex(parent,index)
  191. DbEntry *parent;
  192. int index;
  193. {
  194.     DbEntry *dbp;
  195.  
  196.     DEBUG2("finding entry with index %d in entries for 0x%x\n",index,parent);
  197.     if (parent == NULL) {
  198.     fprintf(stderr,"DB error: attempt to find index %d in NULL list",index);
  199.     return(NULL);
  200.     } else {
  201.     for (dbp=parent->entries; dbp != NULL && index--; dbp=dbp->next)
  202.         /* EMPTY */ ;
  203.     DEBUG1("  find returning 0x%x\n",dbp);
  204.     return(dbp);
  205.     }
  206. }
  207.  
  208. int
  209. findIndexFromEntry(parent,entry)
  210. DbEntry *parent,*entry;
  211. {
  212.     DbEntry *dbp;
  213.     int index;
  214.  
  215.     DEBUG2("finding index for entry 0x%x in entries for 0x%x\n",entry,parent);
  216.     index = 0;
  217.     if (parent == NULL) {
  218.     fprintf(stderr,"DB error: attempt to find entry 0x%x in NULL list",entry);
  219.     return(0);
  220.     } else {
  221.     for (dbp=parent->entries; dbp != NULL; dbp=dbp->next) {
  222.         if (strcmp(entry->name,dbp->name) == 0) {
  223.         DEBUG1("  return index %d\n",index);
  224.         return(index);
  225.         }
  226.         index += 1;
  227.     }
  228.     }
  229.     return(-1);
  230. }
  231.  
  232. /*    -    -    -    -    -    -    -    -    */
  233. /*
  234.  * Allocate and set the data for the given DbEntry.
  235.  */
  236. void
  237. setEntryData(dbp,name,type,size,modes,date,gt_date,vlink)
  238. DbEntry *dbp;
  239. char *name;
  240. int type;
  241. int size;
  242. char *modes,*date,*gt_date;
  243. VLINK vlink;
  244. {
  245.     XtFree(dbp->name);
  246.     dbp->name = XtNewString(name);
  247.     dbp->type = type;
  248.     dbp->size = size;
  249.     dbp->modes = XtNewString(modes);
  250.     dbp->date = XtNewString(date);
  251.     dbp->gt_date = XtNewString(gt_date);
  252.     dbp->vlink = vlink;
  253.     DEBUG2("set data for entry 0x%x, name=\"%s\"\n",dbp,dbp->name);
  254. }
  255.  
  256. /*
  257.  * Free up anything associated with the given DbEntry.
  258.  */
  259. void
  260. freeEntryData(dbp)
  261. DbEntry *dbp;
  262. {
  263.     XtFree((char *)(dbp->name));
  264.     if (dbp->vlink)
  265.     vlfree(dbp->vlink);
  266. }
  267.  
  268. /*    -    -    -    -    -    -    -    -    */
  269. /*
  270.  * Sorts entries of parent and then calls itself on each of them.
  271.  */
  272. void
  273. sortEntriesRecursively(parent,cmp_proc)
  274. DbEntry *parent;
  275. int (*cmp_proc)();
  276. {
  277.     DbEntry *dbp;
  278.  
  279.     if (parent == NULL || cmp_proc == NULL)
  280.     return;
  281.     DEBUG1(" sorting entries recursively for 0x%x\n",parent);
  282.     sortEntries(parent,cmp_proc);
  283.     for (dbp=parent->entries; dbp != NULL; dbp = dbp->next)
  284.     sortEntriesRecursively(dbp->entries,cmp_proc);
  285.     DEBUG1(" done sorting entries recursively for 0x%x\n",parent);
  286. }
  287.  
  288. /*
  289.  * Sorts entries of parent using a selection sort and the given cmp_proc.
  290.  */
  291. void
  292. sortEntries(parent,cmp_proc)
  293. DbEntry *parent;
  294. int (*cmp_proc)();
  295. {
  296.     DbEntry *p,*nextp,*lowest,*q,*pnext,*pprev;
  297.  
  298.     DEBUG1("  sorting entries for 0x%x\n",parent);
  299.     for (p = parent->entries; p != NULL; p = nextp) {
  300.     nextp = p->next;
  301.     lowest = p;
  302.     for (q = p->next; q != NULL; q = q->next)
  303.         if ((*cmp_proc)(q,lowest) < 0)
  304.         lowest = q;
  305.     if (p != lowest) {
  306.         /* swap the two links */
  307.         pnext = p->next;
  308.         pprev = p->prev;
  309.         if (lowest->next != NULL)
  310.         lowest->next->prev = p;
  311.         p->next = lowest->next;
  312.         if (nextp == lowest) {
  313.         p->prev = lowest;
  314.         } else {
  315.         lowest->prev->next = p;
  316.         p->prev = lowest->prev;
  317.         }
  318.         if (nextp == lowest) {
  319.         lowest->next = p;
  320.         } else {
  321.         pnext->prev = lowest;
  322.         lowest->next = pnext;
  323.         }
  324.         if (pprev != NULL)
  325.         pprev->next = lowest;
  326.         lowest->prev = pprev;
  327.         /* keep the head of the list in the right place */
  328.         if (parent->entries == p)
  329.         parent->entries = lowest;
  330.     }
  331.     }
  332.     DEBUG1("  done sorting entries for 0x%x\n",parent);
  333. }
  334.  
  335. /*
  336.  * cmpEntryNames(p,q) : Compare entries by name. Returns < 0 if p belongs
  337.  *    before q, > 0 if q belongs before p, and == 0 if names are identical.
  338.  */
  339. int
  340. cmpEntryNames(p,q)
  341. DbEntry *p,*q;
  342. {
  343.     return(strcmp(p->name,q->name));
  344. }
  345.  
  346. /*
  347.  * cmpEntryDates(p,q) : Compare entries by date. If the dates are the same
  348.  *    or both entries don't have a date, then compare by name.
  349.  *
  350.  * To make this useful, I've made it sort hosts and locations by the
  351.  * newest thing in them. To make it faster, it caches the computed date
  352.  * in the otherwise unused date field.
  353.  */
  354. int
  355. cmpEntryDates(p,q)
  356. DbEntry *p,*q;
  357. {
  358.     int result;
  359.  
  360.     if (!*(p->gt_date))
  361.     p->gt_date = entryDate(p);
  362.     if (!*(q->gt_date))
  363.     q->gt_date = entryDate(q);
  364.     if ((result=strcmp(q->gt_date,p->gt_date)) != 0) /* note order! */
  365.     return(result);
  366.     else
  367.     return(cmpEntryNames(p,q));
  368. }
  369.  
  370. static char *
  371. entryDate(dbp)
  372. DbEntry *dbp;
  373. {
  374.     if (dbp->type == DB_HOST)
  375.     return(hostDate(dbp));
  376.     else if (dbp->type == DB_LOCATION)
  377.     return(locationDate(dbp));
  378.     else
  379.     return(dbp->gt_date);
  380. }
  381.  
  382. /*
  383.  * Returns the date of the newest (biggest date) location in the host.
  384.  */
  385. static char *
  386. hostDate(dbp)
  387. DbEntry *dbp;
  388. {
  389.     DbEntry *loc;
  390.     char *date = "";
  391.     char *locdate;
  392.  
  393.     for (loc=dbp->entries; loc != NULL; loc=loc->next) {
  394.     locdate = locationDate(loc);
  395.     if (!*date || strcmp(date,locdate) < 0)
  396.         date = locdate;
  397.     }
  398.     return(date);
  399. }
  400.  
  401. /*
  402.  * Returns the date of the newest (biggest date) entry in the location.
  403.  */
  404. static char *
  405. locationDate(dbp)
  406. DbEntry *dbp;
  407. {
  408.     DbEntry *file;
  409.     char *date = "";
  410.  
  411.     for (file=dbp->entries; file != NULL; file=file->next) {
  412.     if (!*date || strcmp(date,file->gt_date) < 0)
  413.         date = file->gt_date;
  414.     }
  415.     return(date);
  416. }
  417.  
  418. /*
  419.  * cmpEntryWeights(p,q) : Compare entries by user-defined "weights".
  420.  */
  421. int
  422. cmpEntryWeights(p,q)
  423. DbEntry *p,*q;
  424. {
  425.     int result;
  426.  
  427.     if ((result=hostWeight(p->name)-hostWeight(q->name)) != 0)
  428.     return(result);
  429.     else
  430.     return(cmpEntryNames(p,q));
  431. }
  432.